package redecolaborativa.server.gerentes;



import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import redecolaborativa.server.enums.TipoDeMensagem;
import redecolaborativa.server.excecoes.*;
import redecolaborativa.server.objetos.Mensagem;
import redecolaborativa.server.sistema.Usuario;


public class GerenciadorDeMensagens implements Serializable {
	private static final long serialVersionUID = 1L;
	private Map<String, Map<String, List<String>>> mensagens;
	
	public GerenciadorDeMensagens() {
		mensagens = new HashMap<String, Map<String, List<String>>>();
	}
	
	/**
	 * Retorna as mensagens do usuario.
	 * @return As mensagens do usuario.
	 */
	public Map<String, Map<String, List<String>>> getMensagens() {
		return new HashMap<String, Map<String,List<String>>>(mensagens);
	}
	
	/**
	 * Envia uma mensagem para um Usuario.
	 * @param Mensagem a ser enviada
	 * @param Amigo ao qual quer enviar uma mensagem
	 * @throws DescricaoInvalidaException 
	 * @throws AssuntoInvalidoException 
	 * @throws TipoDeMensagemInvalido 
	 */
	public String enviaMensagem(TipoDeMensagem tipo, String assunto, String descricao, Usuario destinatario) throws TipoDeMensagemInvalido, AssuntoInvalidoException, DescricaoInvalidaException {
		Mensagem mensagem = new Mensagem(tipo, assunto, descricao);
		destinatario.gerenteDeMsg().adiciona(mensagem);
		adiciona(mensagem);
		return destinatario.gerenteDeMsg().retornaIDTopicoMensagem(mensagem.getAssunto());
	}

	/**
	 * Adiciona uma mensagem a lista de mensagens do usuario.
	 * @param Mensagem a ser adicionada
	 */
	public void adiciona(Mensagem mensagem) {
		if (mensagens.containsKey(mensagem.getTipoDeMensagem())) {
			if (mensagens.get(mensagem.getTipoDeMensagem()).containsKey(mensagem.getAssunto())) {
				mensagens.get(mensagem.getTipoDeMensagem()).get(mensagem.getAssunto()).add(mensagem.getDescricao());
			} else {
				List<String> lista = new LinkedList<String>();
				lista.add(mensagem.getDescricao());
				mensagens.get(mensagem.getTipoDeMensagem()).put(mensagem.getAssunto(), lista);
			}
		} else {
			Map<String, List<String>> mapa = new HashMap<String, List<String>>();
			List<String> lista = new LinkedList<String>();
			lista.add(mensagem.getDescricao());
			mapa.put(mensagem.getAssunto(), lista);
			mensagens.put(mensagem.getTipoDeMensagem(), mapa);
		} 
	}
	
	/**
	 * Retorna um ID para um topico de uma mensagem enviada ao usuario.
	 * @param assunto Assunto da mensagem(topico).
	 * @return Um ID que representa o topico da mensagem.
	 */
	public String retornaIDTopicoMensagem(String assunto) {
		Iterator<String> itChave =  mensagens.keySet().iterator();
		while (itChave.hasNext()){
			String tipo = itChave.next();
			Iterator<String> itChaveDoValor = mensagens.get(tipo).keySet().iterator();
			while (itChaveDoValor.hasNext()) {
				String topico = itChaveDoValor.next();
				if (assunto.trim().equalsIgnoreCase(topico.trim())) {
					return topico;
				}
			}
		} return "";
	}
	
	/**
	 * Retorna um string contendo os topicos de mensagens de um usuario.
	 * @param usuario Usuario logado no sistema.
	 * @param tipo Tipo de topico desejado: off-topic, negociacao ou todos.
	 * @return Um string contendo os topicos de mensagens de um usuario.
	 * @throws TipoInvalidoException
	 */
	public String topicosMsg(Usuario usuario, String tipo) throws TipoInvalidoException {
		if(tipo == null || tipo.trim().equals("")) {
			throw new TipoInvalidoException("Tipo inválido");
		} if(!tipo.equalsIgnoreCase(TipoDeMensagem.NEGOCIACAO.name()) && !tipo.equalsIgnoreCase(TipoDeMensagem.OFFTOPIC.name()) && !tipo.equals("todos")) {
			throw new TipoInvalidoException("Tipo inexistente");
		} if(tipo.equalsIgnoreCase(TipoDeMensagem.NEGOCIACAO.name())) {
			return topicosDeMensagensDeNegociacao(usuario);
		} if(tipo.equalsIgnoreCase(TipoDeMensagem.OFFTOPIC.name())) {
			return topicosDeMensagensOffTopic(usuario);
		} if(tipo.equals("todos")) {
			return topicosDeMensagensDeTodosOsTipos(usuario);
		} return "";
	}
	
	/*
	 * Retorna uma string contendo os topicos de mensagens de um usuario do tipo negociacao.
	 */
	private String topicosDeMensagensDeNegociacao(Usuario usuario) {
		if(usuario.gerenteDeMsg().getMensagens().get(TipoDeMensagem.NEGOCIACAO.name()) == null) {
			return "Não há tópicos criados";
		} 
		Set<String> topicos = usuario.gerenteDeMsg().getMensagens().get(TipoDeMensagem.NEGOCIACAO.name()).keySet();
		Iterator<String> it = topicos.iterator();
		String retorno = "";
		while (it.hasNext()) {
			retorno += (it.next() + "; ");
		} 
		return retorno.substring(0, retorno.length()-2);
	}
	
	/*
	 * Retorna uma string contendo os topicos de mensagens de um usuario do tipo off-topic.
	 */
	private String topicosDeMensagensOffTopic(Usuario usuario) {
		if(usuario.gerenteDeMsg().getMensagens().get(TipoDeMensagem.OFFTOPIC.name()) == null) {
			return "Não há tópicos criados";
		}
		Set<String> topicos = usuario.gerenteDeMsg().getMensagens().get(TipoDeMensagem.OFFTOPIC.name()).keySet();
		Iterator<String> it = topicos.iterator();
		String retorno = "";
		while (it.hasNext()) {
			retorno += (it.next() + "; ");
		} 
		return retorno.substring(0, retorno.length()-2);
	}
	
	/*
	 * Retorna uma string contendo os topicos de mensagens de um usuario de todos os tipos.
	 */
	private String topicosDeMensagensDeTodosOsTipos(Usuario usuario) {
		if(topicosDeMensagensDeNegociacao(usuario).equals("Não há tópicos criados") && topicosDeMensagensOffTopic(usuario).equals("Não há tópicos criados")) {
			return "Não há tópicos criados";
		} if(topicosDeMensagensDeNegociacao(usuario).equals("Não há tópicos criados")) {
			return topicosDeMensagensOffTopic(usuario);
		} if(topicosDeMensagensOffTopic(usuario).equals("Não há tópicos criados")) {
			return topicosDeMensagensDeNegociacao(usuario);
		} 
		return String.format("%s; %s", topicosDeMensagensDeNegociacao(usuario), topicosDeMensagensOffTopic(usuario));
	}
}